/****************************************************************************
 *
 * Copyright 2016 Samsung Electronics All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 *
 ****************************************************************************/
/************************************************************************
 * libc/string/lib_strerror.c
 *
 *   Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name NuttX nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ************************************************************************/

/************************************************************************
 * Included Files
 ************************************************************************/

#include <tinyara/config.h>

#include <stdint.h>
#include <string.h>
#include <errno.h>

/************************************************************************
 * Definitions
 ************************************************************************/

/************************************************************************
 * Private Types
 ************************************************************************/

struct errno_strmap_s {
	uint8_t errnum;
	const char *str;
};

/************************************************************************
 * Private Data
 ************************************************************************/

#ifdef CONFIG_LIBC_STRERROR

/* This table maps all error numbers to descriptive strings.
 * The only assumption that the code makes with regard to this
 * this table is that it is ordered by error number.
 *
 * The size of this table is quite large.  Its size can be
 * reduced by eliminating some of the more obscure error
 * strings.
 */

#ifndef CONFIG_LIBC_STRERROR_SHORT

static const struct errno_strmap_s g_errnomap[] = {
	{EPERM, EPERM_STR},
	{ENOENT, ENOENT_STR},
	{ESRCH, ESRCH_STR},
	{EINTR, EINTR_STR},
	{EIO, EIO_STR},
	{ENXIO, ENXIO_STR},
	{E2BIG, E2BIG_STR},
	{ENOEXEC, ENOEXEC_STR},
	{EBADF, EBADF_STR},
	{ECHILD, ECHILD_STR},
	{EAGAIN, EAGAIN_STR},
	{ENOMEM, ENOMEM_STR},
	{EACCES, EACCES_STR},
	{EFAULT, EFAULT_STR},
	{ENOTBLK, ENOTBLK_STR},
	{EBUSY, EBUSY_STR},
	{EEXIST, EEXIST_STR},
	{EXDEV, EXDEV_STR},
	{ENODEV, ENODEV_STR},
	{ENOTDIR, ENOTDIR_STR},
	{EISDIR, EISDIR_STR},
	{EINVAL, EINVAL_STR},
	{ENFILE, ENFILE_STR},
	{EMFILE, EMFILE_STR},
	{ENOTTY, ENOTTY_STR},
	{ETXTBSY, ETXTBSY_STR},
	{EFBIG, EFBIG_STR},
	{ENOSPC, ENOSPC_STR},
	{ESPIPE, ESPIPE_STR},
	{EROFS, EROFS_STR},
	{EMLINK, EMLINK_STR},
	{EPIPE, EPIPE_STR},
	{EDOM, EDOM_STR},
	{ERANGE, ERANGE_STR},
	{EDEADLK, EDEADLK_STR},
	{ENAMETOOLONG, ENAMETOOLONG_STR},
	{ENOLCK, ENOLCK_STR},
	{ENOSYS, ENOSYS_STR},
	{ENOTEMPTY, ENOTEMPTY_STR},
	{ELOOP, ELOOP_STR},
	{ENOMSG, ENOMSG_STR},
	{EIDRM, EIDRM_STR},
	{ECHRNG, ECHRNG_STR},
	{EL2NSYNC, EL2NSYNC_STR},
	{EL3HLT, EL3HLT_STR},
	{EL3RST, EL3RST_STR},
	{ELNRNG, ELNRNG_STR},
	{EUNATCH, EUNATCH_STR},
	{ENOCSI, ENOCSI_STR},
	{EL2HLT, EL2HLT_STR},
	{EBADE, EBADE_STR},
	{EBADR, EBADR_STR},
	{EXFULL, EXFULL_STR},
	{ENOANO, ENOANO_STR},
	{EBADRQC, EBADRQC_STR},
	{EBADSLT, EBADSLT_STR},
	{EBFONT, EBFONT_STR},
	{ENOSTR, ENOSTR_STR},
	{ENODATA, ENODATA_STR},
	{ETIME, ETIME_STR},
	{ENOSR, ENOSR_STR},
	{ENONET, ENONET_STR},
	{ENOPKG, ENOPKG_STR},
	{EREMOTE, EREMOTE_STR},
	{ENOLINK, ENOLINK_STR},
	{EADV, EADV_STR},
	{ESRMNT, ESRMNT_STR},
	{ECOMM, ECOMM_STR},
	{EPROTO, EPROTO_STR},
	{EMULTIHOP, EMULTIHOP_STR},
	{EDOTDOT, EDOTDOT_STR},
	{EBADMSG, EBADMSG_STR},
	{EOVERFLOW, EOVERFLOW_STR},
	{ENOTUNIQ, ENOTUNIQ_STR},
	{EBADFD, EBADFD_STR},
	{EREMCHG, EREMCHG_STR},
	{ELIBACC, ELIBACC_STR},
	{ELIBBAD, ELIBBAD_STR},
	{ELIBSCN, ELIBSCN_STR},
	{ELIBMAX, ELIBMAX_STR},
	{ELIBEXEC, ELIBEXEC_STR},
	{EILSEQ, EILSEQ_STR},
	{ERESTART, ERESTART_STR},
	{ESTRPIPE, ESTRPIPE_STR},
	{EUSERS, EUSERS_STR},
	{ENOTSOCK, ENOTSOCK_STR},
	{EDESTADDRREQ, EDESTADDRREQ_STR},
	{EMSGSIZE, EMSGSIZE_STR},
	{EPROTOTYPE, EPROTOTYPE_STR},
	{ENOPROTOOPT, ENOPROTOOPT_STR},
	{EPROTONOSUPPORT, EPROTONOSUPPORT_STR},
	{ESOCKTNOSUPPORT, ESOCKTNOSUPPORT_STR},
	{EOPNOTSUPP, EOPNOTSUPP_STR},
	{EPFNOSUPPORT, EPFNOSUPPORT_STR},
	{EAFNOSUPPORT, EAFNOSUPPORT_STR},
	{EADDRINUSE, EADDRINUSE_STR},
	{EADDRNOTAVAIL, EADDRNOTAVAIL_STR},
	{ENETDOWN, ENETDOWN_STR},
	{ENETUNREACH, ENETUNREACH_STR},
	{ENETRESET, ENETRESET_STR},
	{ECONNABORTED, ECONNABORTED_STR},
	{ECONNRESET, ECONNRESET_STR},
	{ENOBUFS, ENOBUFS_STR},
	{EISCONN, EISCONN_STR},
	{ENOTCONN, ENOTCONN_STR},
	{ESHUTDOWN, ESHUTDOWN_STR},
	{ETOOMANYREFS, ETOOMANYREFS_STR},
	{ETIMEDOUT, ETIMEDOUT_STR},
	{ECONNREFUSED, ECONNREFUSED_STR},
	{EHOSTDOWN, EHOSTDOWN_STR},
	{EHOSTUNREACH, EHOSTUNREACH_STR},
	{EALREADY, EALREADY_STR},
	{EINPROGRESS, EINPROGRESS_STR},
	{ESTALE, ESTALE_STR},
	{EUCLEAN, EUCLEAN_STR},
	{ENOTNAM, ENOTNAM_STR},
	{ENAVAIL, ENAVAIL_STR},
	{EISNAM, EISNAM_STR},
	{EREMOTEIO, EREMOTEIO_STR},
	{EDQUOT, EDQUOT_STR},
	{ENOMEDIUM, ENOMEDIUM_STR},
	{EMEDIUMTYPE, EMEDIUMTYPE_STR}
};

#else							/* CONFIG_LIBC_STRERROR_SHORT */

static const struct errno_strmap_s g_errnomap[] = {
	{EPERM, "EPERM"},
	{ENOENT, "ENOENT"},
	{ESRCH, "ESRCH"},
	{EINTR, "EINTR"},
	{EIO, "EIO"},
	{ENXIO, "ENXIO"},
	{E2BIG, "E2BIG"},
	{ENOEXEC, "ENOEXEC"},
	{EBADF, "EBADF"},
	{ECHILD, "ECHILD"},
	{EAGAIN, "EAGAIN"},
	{ENOMEM, "ENOMEM"},
	{EACCES, "EACCES"},
	{EFAULT, "EFAULT"},
	{ENOTBLK, "ENOTBLK"},
	{EBUSY, "EBUSY"},
	{EEXIST, "EEXIST"},
	{EXDEV, "EXDEV"},
	{ENODEV, "ENODEV"},
	{ENOTDIR, "ENOTDIR"},
	{EISDIR, "EISDIR"},
	{EINVAL, "EINVAL"},
	{ENFILE, "ENFILE"},
	{EMFILE, "EMFILE"},
	{ENOTTY, "ENOTTY"},
	{ETXTBSY, "ETXTBSY"},
	{EFBIG, "EFBIG"},
	{ENOSPC, "ENOSPC"},
	{ESPIPE, "ESPIPE"},
	{EROFS, "EROFS"},
	{EMLINK, "EMLINK"},
	{EPIPE, "EPIPE"},
	{EDOM, "EDOM"},
	{ERANGE, "ERANGE"},
	{EDEADLK, "EDEADLK"},
	{ENAMETOOLONG, "ENAMETOOLONG"},
	{ENOLCK, "ENOLCK"},
	{ENOSYS, "ENOSYS"},
	{ENOTEMPTY, "ENOTEMPTY"},
	{ELOOP, "ELOOP"},
	{ENOMSG, "ENOMSG"},
	{EIDRM, "EIDRM"},
	{ECHRNG, "ECHRNG"},
	{EL2NSYNC, "EL2NSYNC"},
	{EL3HLT, "EL3HLT"},
	{EL3RST, "EL3RST"},
	{EL3RST, "EL3RST"},
	{EUNATCH, "EUNATCH"},
	{ENOCSI, "ENOCSI"},
	{EL2HLT, "EL2HLT"},
	{EBADE, "EBADE"},
	{EBADR, "EBADR"},
	{EXFULL, "EXFULL"},
	{ENOANO, "ENOANO"},
	{EBADRQC, "EBADRQC"},
	{EBADSLT, "EBADSLT"},
	{EBFONT, "EBFONT"},
	{ENOSTR, "ENOSTR"},
	{ENODATA, "ENODATA"},
	{ETIME, "ETIME"},
	{ENOSR, "ENOSR"},
	{ENONET, "ENONET"},
	{ENOPKG, "ENOPKG"},
	{EREMOTE, "EREMOTE"},
	{ENOLINK, "ENOLINK"},
	{EADV, "EADV"},
	{ESRMNT, "ESRMNT"},
	{ECOMM, "ECOMM"},
	{EPROTO, "EPROTO"},
	{EMULTIHOP, "EMULTIHOP"},
	{EDOTDOT, "EDOTDOT"},
	{EBADMSG, "EBADMSG"},
	{EOVERFLOW, "EOVERFLOW"},
	{ENOTUNIQ, "ENOTUNIQ"},
	{EBADFD, "EBADFD"},
	{EREMCHG, "EREMCHG"},
	{ELIBACC, "ELIBACC"},
	{ELIBBAD, "ELIBBAD"},
	{ELIBSCN, "ELIBSCN"},
	{ELIBMAX, "ELIBMAX"},
	{ELIBEXEC, "ELIBEXEC"},
	{EILSEQ, "EILSEQ"},
	{ERESTART, "ERESTART"},
	{ESTRPIPE, "ESTRPIPE"},
	{EUSERS, "EUSERS"},
	{ENOTSOCK, "ENOTSOCK"},
	{EDESTADDRREQ, "EDESTADDRREQ"},
	{EMSGSIZE, "EMSGSIZE"},
	{EPROTOTYPE, "EPROTOTYPE"},
	{ENOPROTOOPT, "ENOPROTOOPT"},
	{EPROTONOSUPPORT, "EPROTONOSUPPORT"},
	{ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"},
	{EOPNOTSUPP, "EOPNOTSUPP"},
	{EPFNOSUPPORT, "EPFNOSUPPORT"},
	{EAFNOSUPPORT, "EAFNOSUPPORT"},
	{EADDRINUSE, "EADDRINUSE"},
	{EADDRNOTAVAIL, "EADDRNOTAVAIL"},
	{ENETDOWN, "ENETDOWN"},
	{ENETUNREACH, "ENETUNREACH"},
	{ENETRESET, "ENETRESET"},
	{ECONNABORTED, "ECONNABORTED"},
	{ECONNRESET, "ECONNRESET"},
	{ENOBUFS, "ENOBUFS"},
	{EISCONN, "EISCONN"},
	{ENOTCONN, "ENOTCONN"},
	{ESHUTDOWN, "ESHUTDOWN"},
	{ETOOMANYREFS, "ETOOMANYREFS"},
	{ETIMEDOUT, "ETIMEDOUT"},
	{ECONNREFUSED, "ECONNREFUSED"},
	{EHOSTDOWN, "EHOSTDOWN"},
	{EHOSTUNREACH, "EHOSTUNREACH"},
	{EALREADY, "EALREADY"},
	{EINPROGRESS, "EINPROGRESS"},
	{ESTALE, "ESTALE"},
	{EUCLEAN, "EUCLEAN"},
	{ENOTNAM, "ENOTNAM"},
	{ENAVAIL, "ENAVAIL"},
	{EISNAM, "EISNAM"},
	{EREMOTEIO, "EREMOTEIO"},
	{EDQUOT, "EDQUOT"},
	{ENOMEDIUM, "ENOMEDIUM"},
	{EMEDIUMTYPE, "EMEDIUMTYPE"}
};

#endif							/* CONFIG_LIBC_STRERROR_SHORT */

#define NERRNO_STRS (sizeof(g_errnomap) / sizeof(struct errno_strmap_s))

#endif							/* CONFIG_LIBC_STRERROR */

/************************************************************************
 * Private Functions
 ************************************************************************/

/************************************************************************
 * Public Functions
 ************************************************************************/

/************************************************************************
 * Name: strerror
 ************************************************************************/

FAR const char *strerror(int errnum)
{
#ifdef CONFIG_LIBC_STRERROR
	int ndxlow = 0;
	int ndxhi = NERRNO_STRS - 1;
	int ndxmid;

	do {
		ndxmid = (ndxlow + ndxhi) >> 1;
		if (errnum > g_errnomap[ndxmid].errnum) {
			ndxlow = ndxmid + 1;
		} else if (errnum < g_errnomap[ndxmid].errnum) {
			ndxhi = ndxmid - 1;
		} else {
			return g_errnomap[ndxmid].str;
		}
	} while (ndxlow <= ndxhi);
#endif
	return "Unknown error";
}
